#include "stdafx.h"
#include "net/MemoryPool.hpp"
#include "stdlib/exception.hpp"
using namespace JHCPP::stdlib::jhException;

NET_NAMESPACE_BEGIN

CMemoryPool::CMemoryPool(std::size_t blockSize, int preAlloc, int maxAlloc)
	: m_blockSize(blockSize),
	m_maxAlloc(maxAlloc),
	m_allocated(preAlloc)
{
	jh_assert (maxAlloc == 0 || maxAlloc >= preAlloc);
	jh_assert (preAlloc >= 0 && maxAlloc >= 0);

	int r = BLOCK_RESERVE;
	if (preAlloc > r)
		r = preAlloc;
	if (maxAlloc > 0 && maxAlloc < r)
		r = maxAlloc;
	m_blocks.reserve(r);
	for (int i = 0; i < preAlloc; ++i)
	{
		m_blocks.push_back(new char[m_blockSize]);
	}
}

CMemoryPool::~CMemoryPool()
{
	for (BlockVec::iterator it = m_blocks.begin(); it != m_blocks.end(); ++it)
	{
		delete [] *it;
	}
}

void* CMemoryPool::get()
{
	CMutex::ScopedLock lock(m_mutex);

	if (m_blocks.empty())
	{
		if (m_maxAlloc == 0 || m_allocated < m_maxAlloc)
		{
			++m_allocated;
			return new char[m_blockSize];
		}
		else 
			throw OutOfMemoryException("MemoryPool exhausted");
	}
	else
	{
		char* ptr = m_blocks.back();
		m_blocks.pop_back();
		return ptr;
	}
}

void CMemoryPool::release(void* ptr)
{
	CMutex::ScopedLock lock(m_mutex);

	m_blocks.push_back(reinterpret_cast<char*>(ptr));
}

std::size_t CMemoryPool::blockSize() const
{
	return m_blockSize;
}

int CMemoryPool::allocated() const
{
	return m_allocated;
}

int CMemoryPool::available() const
{
	return (int) m_blocks.size();
}

NET_NAMESPACE_END
